using System.Diagnostics;
using System.IO;
using FileTransfer.Client.Upload;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FileTransfer.Client.Test;

[TestClass]
public class PerformanceTest
{
    private readonly ILogger<ShareCollection> _logger;

    private readonly ILoggerFactory _loggerFactory;
    private ApiClient api = ApiHelper.NewApiClient(null);

    public PerformanceTest()
    {
        _loggerFactory = LoggerFactory.Create(builder =>
            builder.AddConsole().SetMinimumLevel(LogLevel.Information)
        );
        _logger = _loggerFactory.CreateLogger<ShareCollection>();
    }

    /// <summary>
    /// 生成指定大小的随机文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="size">文件大小（字节）</param>
    private static async Task GenerateRandomFileAsync(string filePath, long size)
    {
        var file = new FileInfo(filePath);
        await using var fos = file.Create();

        var random = new Random();
        var buffer = new byte[1024 * 1024]; // 1MB buffer
        long remaining = size;

        while (remaining > 0)
        {
            int bytesToWrite = (int)Math.Min(buffer.Length, remaining);
            random.NextBytes(buffer); // 填充随机字节
            await fos.WriteAsync(buffer, 0, bytesToWrite);
            remaining -= bytesToWrite;
        }
    }

    [DataTestMethod]
    [DataRow(1024 * 1024, "1MB文件")] // 1 MB
    [DataRow(1024 * 1024 * 5, "5MB文件")] // 5 MB
    [DataRow(1024 * 1024 * 10, "10MB文件")] // 10 MB
    public async Task TestFileUploadPerformance(long fileSize, string description)
    {
        string filePath = $"perf_test_{fileSize}.bin";

        try
        { // 生成测试文件
            var stopwatch = Stopwatch.StartNew();
            await GenerateRandomFileAsync(filePath, fileSize);
            stopwatch.Stop();

            _logger.LogInformation(
                "{Description} 生成耗时：{ElapsedMs}ms",
                description,
                stopwatch.ElapsedMilliseconds
            );

            // 测试不同的chunk size对性能的影响
            int[] chunkSizes = { 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024 }; // 1MB, 2MB, 4MB

            foreach (var chunkSize in chunkSizes)
            {
                await TestUploadWithChunkSize(filePath, chunkSize, description);
            }
        }
        finally
        {
            // 清理测试文件
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }
        }
    }

    private async Task TestUploadWithChunkSize(string filePath, int chunkSize, string description)
    {
        var shareCollection = new ShareCollection(api, chunkSize, _loggerFactory);
        var progressList = new List<ProgressInfo>();

        var stopwatch = Stopwatch.StartNew();

        await shareCollection.AddFileAsync(
            new FileInfo(filePath),
            progressInfo =>
            {
                progressList.Add(progressInfo);
                if (progressInfo.ProgressPercentage % 10 == 0) // 每10%记录一次
                {
                    _logger.LogInformation(
                        "{Description} - Chunk大小：{ChunkSize}KB - 进度：{Progress}%",
                        description,
                        chunkSize / 1024,
                        progressInfo.ProgressPercentage
                    );
                }
            }
        );

        var result = await shareCollection.MakeShareAsync();
        stopwatch.Stop();

        _logger.LogInformation(
            "{Description} - Chunk大小：{ChunkSize}KB - 总耗时：{ElapsedMs}ms - 分享码：{ShareCode}",
            description,
            chunkSize / 1024,
            stopwatch.ElapsedMilliseconds,
            result.Share.Code
        ); // 验证上传成功
        Assert.IsNotNull(result.Share.Code);
        Assert.IsTrue(result.Links.Count > 0);
        Assert.IsTrue(progressList.Count > 0);

        // 验证进度报告的正确性
        var lastProgress = progressList.Last();
        Assert.AreEqual(100, lastProgress.ProgressPercentage);
    }

    [TestMethod]
    public async Task TestConcurrentFileUploads()
    {
        const int fileCount = 3;
        const long fileSize = 1024 * 1024 * 2; // 2 MB per file
        var tasks = new List<Task>();
        var results = new List<ShareCollection.ShareResultToken>();
        var lockObject = new object();

        for (int i = 0; i < fileCount; i++)
        {
            int fileIndex = i; // 捕获循环变量
            tasks.Add(
                Task.Run(async () =>
                {
                    string filePath = $"concurrent_test_{fileIndex}.bin";
                    try
                    {
                        // 生成测试文件
                        await GenerateRandomFileAsync(filePath, fileSize);

                        // 上传文件
                        var shareCollection = new ShareCollection(api, 1024 * 1024, _loggerFactory);
                        await shareCollection.AddFileAsync(
                            new FileInfo(filePath),
                            progressInfo =>
                            {
                                _logger.LogInformation(
                                    "文件{FileIndex} 上传进度：{Progress}%",
                                    fileIndex,
                                    progressInfo.ProgressPercentage
                                );
                            }
                        );

                        var result = await shareCollection.MakeShareAsync();

                        lock (lockObject)
                        {
                            results.Add(result);
                        }

                        _logger.LogInformation(
                            "文件{FileIndex} 上传完成，分享码：{ShareCode}",
                            fileIndex,
                            result.Share.Code
                        );
                    }
                    finally
                    {
                        // 清理测试文件
                        if (File.Exists(filePath))
                        {
                            File.Delete(filePath);
                        }
                    }
                })
            );
        }

        var stopwatch = Stopwatch.StartNew();
        await Task.WhenAll(tasks);
        stopwatch.Stop();

        _logger.LogInformation(
            "并发上传{FileCount}个文件总耗时：{ElapsedMs}ms",
            fileCount,
            stopwatch.ElapsedMilliseconds
        ); // 验证所有文件都上传成功
        Assert.AreEqual(fileCount, results.Count);
        foreach (var result in results)
        {
            Assert.IsNotNull(result.Share.Code);
            Assert.IsTrue(result.Links.Count > 0);
        }
    }

    [TestMethod]
    public async Task TestMemoryUsageDuringUpload()
    {
        const long fileSize = 1024 * 1024 * 50; // 50 MB
        string filePath = "memory_test.bin";
        try
        {
            // 生成大文件
            await GenerateRandomFileAsync(filePath, fileSize);

            // 记录开始内存
            var initialMemory = GC.GetTotalMemory(true);
            _logger.LogInformation("上传前内存使用：{Memory} bytes", initialMemory);

            var shareCollection = new ShareCollection(api, 2 * 1024 * 1024, _loggerFactory); // 2MB chunks

            await shareCollection.AddFileAsync(
                new FileInfo(filePath),
                progressInfo =>
                {
                    if (progressInfo.ProgressPercentage % 25 == 0) // 每25%检查一次内存
                    {
                        var currentMemory = GC.GetTotalMemory(false);
                        _logger.LogInformation(
                            "进度：{Progress}% - 当前内存使用：{Memory} bytes",
                            progressInfo.ProgressPercentage,
                            currentMemory
                        );
                    }
                }
            );

            var result = await shareCollection.MakeShareAsync();

            // 强制垃圾回收并记录最终内存
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            var finalMemory = GC.GetTotalMemory(true);
            _logger.LogInformation("上传后内存使用：{Memory} bytes", finalMemory);
            _logger.LogInformation("内存增长：{MemoryDiff} bytes", finalMemory - initialMemory); // 验证上传成功
            Assert.IsNotNull(result.Share.Code);
            Assert.IsTrue(result.Links.Count > 0);
        }
        finally
        {
            // 清理测试文件
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }
        }
    }
}
